﻿/*
 * Comments.
 * ---------------------------------------------------------------------------------------------------
 * Date         |  Who          |  Version      | Description of Change
 * ---------------------------------------------------------------------------------------------------
 * 28/02/12      Gareth B           Alpha 0.0.2   Added Thumbail Support. CreateThumbnailToByte and
 *                                                CreateThumbnailToImage singleton methods.
 */

using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Bradaz.OpenSource;
using Bradaz.OpenSource.IO;

namespace Bradaz.OpenSource.Images
{
    /// <summary>
    /// IImageModel - Mandatory Signatures that we need
    /// </summary>
    public interface IImageModel
    {
        //-- ImageModel Property Signature.
        Guid UniqueId { get; set; }
        Guid TableLink { get; set; }
        String RecordStatus { get; set; }
        Byte[] Source { get; set; }
        Int32 FileSize { get; set; }
        String FileName { get; set; }
        String FileExtension { get; set; }
        String ContentType { get; set; }
    }

    /// <summary>
    /// Static Utility to deal with common Image Stream tasks.
    /// </summary>
    public static class Images
    {
        /// <summary>
        /// Takes the inputstream and pushes that through a Image.FromStream
        /// to give the bytes needed to store in a Varbinary 
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <returns>Binary File</returns>
        public static byte[] ImageToBinary(Stream stream)
        {
            byte[] file = null;

            //--Set the stream to the beginning before we start.

            using (Image img = Image.FromStream(stream))
            {

                //--Initalise the size of the array

                file = new byte[stream.Length];

                //--Create a new BinaryReader and set the InputStream for the Images InputStream to the
                //--beginning, as we create the img using a stream.
                BinaryReader reader = new BinaryReader(stream);
                Streams.RewindStream(ref stream);

                //--Load the image binary.
                return file = reader.ReadBytes((int)stream.Length);
            }

        }

        /// <summary>
        /// Takes an inputstream and returns an Image height.
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <returns>Image Height</returns>
        public static int FromStreamHeight(Stream stream)
        {

            //--Rewind the memory back to the beginning of the stream.
            Streams.RewindStream(ref stream);

            using (Image img = Image.FromStream(stream))
            {

                return img.Height;
            }
        }

        /// <summary>
        /// Takes an inputstream and returns an Image width.
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <returns>Image Width</returns>
        public static int FromStreamWidth(Stream stream)
        {

            //--Rewind the memory back to the beginning of the stream.
            Streams.RewindStream(ref stream);

            using (Image img = Image.FromStream(stream))
            {

                return img.Width;
            }
        }

        /// <summary>
        /// Takes an byte array and returns an Image height.
        /// </summary>
        /// <param name="image">byte array of an Image.</param>
        /// <returns>Height</returns>
        public static int FromByteHeight(byte[] image)
        {
            Image img;
            int height = 0;

            if (image != null)
            {
                using (MemoryStream stream = new MemoryStream(image))
                {
                    img = Image.FromStream(stream);
                    height = img.Height;

                }
            }

            return height;

        }

        /// <summary>
        /// Takes an byte array and returns an Image width.
        /// </summary>
        /// <param name="image">byte array of an Image.</param>
        /// <returns>Width</returns>
        public static int FromByteWidth(byte[] image)
        {
            Image img;
            int width = 0;

            if (image != null)
            {
                using (MemoryStream stream = new MemoryStream(image))
                {
                    img = Image.FromStream(stream);
                    width = img.Height;

                }
            }

            return width;

        }

        /// <summary>
        /// This method creates a Thumbnail Image and and scales it. It returns a byte array
        /// to be used.
        /// </summary>
        /// <param name="stream">Image Stream</param>
        /// <param name="maxHeight">Max Height (Used to scale the image</param>
        /// <param name="maxWidth">Max Width (Used to scale the image)</param>
        /// <returns>Scaled thumbail image byte array.</returns>
        public static byte[] CreateThumbnailToByte(Stream stream, double maxHeight, double maxWidth)
        {
            int newHeight;
            int newWidth;
            double aspectRatio = 0;
            double boxRatio = 0;
            double scale = 0;

            Stream imageStream = new MemoryStream();
            Image originalImage;

            Streams.RewindStream(ref stream);
            using (originalImage = Image.FromStream(stream))
            {
                //--We need too maintain the aspect ratio on the image.
                aspectRatio = originalImage.Width / originalImage.Height;
                boxRatio = maxWidth / maxHeight;

                if (boxRatio > aspectRatio)
                {
                    scale = maxHeight / originalImage.Height;
                }
                else
                {
                    scale = maxWidth / originalImage.Width;
                }

                //--Scale the Original Images dimensions
                newHeight = (int)(originalImage.Height * scale);
                newWidth = (int)(originalImage.Width * scale);

                using (var bitmap = new Bitmap(newWidth, newHeight))

                //--Create a new GDI+ drawing surfance based on the original Image. This methid allows us to alter
                //--it where necessary, based on advice from here. http://nathanaeljones.com/163/20-image-resizing-pitfalls/
                using (var graphics = Graphics.FromImage(bitmap))
                {
                    var rectangle = new Rectangle(0, 0, newWidth, newHeight);

                    graphics.CompositingQuality = CompositingQuality.HighQuality;
                    graphics.SmoothingMode = SmoothingMode.HighQuality;
                    graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphics.DrawImage(originalImage, rectangle);

                    //--The same image to a new ImageStream so we can convert this to a byte array.
                    bitmap.Save(imageStream, originalImage.RawFormat);

                }

                byte[] thumbnail = new byte[imageStream.Length];
                BinaryReader reader = new BinaryReader(imageStream);
                imageStream.Seek(0, SeekOrigin.Begin);

                //--Load the image binary.
                thumbnail = reader.ReadBytes((int)imageStream.Length);
                return thumbnail;

            }        

       }

        /// <summary>
        /// This method creates a Thumbnail Image and and scales it. It returns a Image
        /// to be used.
        /// </summary>
        /// <param name="stream">Image Stream</param>
        /// <param name="maxHeight">Max Height (Used to scale the image</param>
        /// <param name="maxWidth">Max Width (Used to scale the image)</param>
        /// <returns>Scaled thumbail Image.</returns>
        public static Image CreateThumbnailToImage(Stream stream, double maxHeight, double maxWidth)
        {
            int newHeight;
            int newWidth;
            double aspectRatio = 0;
            double boxRatio = 0;
            double scale = 0;

            Stream imageStream = new MemoryStream();
            Image originalImage;

            using (originalImage = Image.FromStream(stream))
            {
                //--We need too maintain the aspect ratio on the image.
                aspectRatio = originalImage.Width / originalImage.Height;
                boxRatio = maxWidth / maxHeight;

                if (boxRatio > aspectRatio)
                {
                    scale = maxHeight / originalImage.Height;
                }
                else
                {
                    scale = maxWidth / originalImage.Width;
                }

                //--Scale the Original Images dimensions
                newHeight = (int)(originalImage.Height * scale);
                newWidth = (int)(originalImage.Width * scale);


            }

            using (var bitmap = new Bitmap(newWidth, newHeight))

            //--Create a new GDI+ drawing surfance based on the original Image. This methid allows us to alter
            //--it where necessary, based on advice from here. http://nathanaeljones.com/163/20-image-resizing-pitfalls/
            using (var graphics = Graphics.FromImage(bitmap))
            {
                var rectangle = new Rectangle(0, 0, newWidth, newHeight);

                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphics.DrawImage(originalImage, rectangle);

                //--The same image to a new ImageStream so we can convert this to a byte array.
                bitmap.Save(imageStream, originalImage.RawFormat);

            }

            return Image.FromStream(imageStream);

        }


    }
}
